home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dirut / dosdir21.zip / DOSDIR.C < prev    next >
C/C++ Source or Header  |  1994-06-22  |  10KB  |  358 lines

  1. /*
  2.   dosdir.c:
  3.  
  4.   DOSDIR V2.1: A Portable DOS/UNIX/VMS Directory Interface
  5.  
  6.   Implementation of the DOS directory functions (findfirst and findnext)
  7.   on MS-DOS, UNIX and VMS platforms using the appropriate file & directory
  8.   structure.
  9.  
  10.   Provides the DOS directory framework for MS-DOS/UNIX/VMS application
  11.   portability.
  12.  
  13.   Supports MS-DOS with Borland C++, Turbo C, or Microsoft C V6.0/7.0,
  14.   Sun with GNU C compiler, DEC Alpha (OSF-1), VAX/VMS C,
  15.   and other comparable platforms.
  16.  
  17.   Jason Mathews
  18.   NASA/Goddard Space Flight Center
  19.   Code 633.2
  20.   Greenbelt, Maryland  20771-0001 USA
  21.  
  22.   e-mail: mathews@nssdca.gsfc.nasa.gov
  23.  
  24.   Copyright (C) 1994 Jason Mathews.
  25.   Permission is granted to any individual or institution to use, copy,
  26.   redistribute or modify this software so long as it is not sold for
  27.   profit, provided this copyright notice is retained.
  28.  
  29.   Modification history:
  30.    V1.0  02-May-91,  Original version.
  31.    V2.0  13-May-94,  Reimplemented findfirst/findnext with ffblk structure
  32.              to match MS-DOS externally, fixed wildcard evaluation
  33.              function.
  34.    V2.1  08-Jun-94,  Replaced wildcard evaluation function with recursive
  35.              function provided by Info-ZIP's portable UnZip,
  36.              added dd_ prefix to most functions & constants,
  37.              added VMS functions + MSC/TURBOC macros.
  38.   */
  39.  
  40. #include <string.h>
  41. #include "dosdir.h"
  42.  
  43. struct stat dd_sstat;  /* global stat structure of last successful file
  44.             * returned by findfirst/findnext functions available
  45.             * to query for more detailed information.
  46.             */
  47.  
  48. #ifdef MSDOS
  49. #  ifdef __TURBOC__
  50. #    define FSTRUCT        struct ffblk
  51. #    define FATTR        FA_HIDDEN+FA_SYSTEM+FA_DIREC
  52. #    define FFIRST(n,d,a)    findfirst(n,d,a)
  53. #    define FNEXT(d)        findnext(d)
  54. #    define FNAME        ff_name
  55. #    define FATTRIB        ff_attrib
  56. #    define FSIZE        ff_fsize
  57. #    define FDATE        ff_fdate
  58. #    define FTIME        ff_ftime
  59. #  else /* !__TURBOC__ */
  60. #    define FSTRUCT        struct find_t
  61. #    define FATTR        _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
  62. #    define FFIRST(n,d,a)    _dos_findfirst(n,a,d)
  63. #    define FNEXT(d)        _dos_findnext(d)
  64. #    define FNAME        name
  65. #    define FATTRIB        attrib
  66. #    define FSIZE        size
  67. #    define FDATE        wr_date
  68. #    define FTIME        wr_time
  69. #  endif /* ?__TURBOC__ */
  70. #else /* ?UNIX/VMS */
  71. #  include "match.h"
  72.  
  73. /* stub functions for get/set disk
  74.  * fake MS-DOS functions that do not apply to unix or vms:
  75.  */
  76.  
  77. int getdisk()
  78. {
  79.   return 0;
  80. }
  81.  
  82. int setdisk( drive )
  83.     int drive;
  84. {
  85.   return 0;
  86. }
  87.  
  88. #endif /* ?MSDOS */
  89.  
  90. #if defined (MSDOS)
  91. #  ifndef __TURBOC__
  92. /*
  93.  * getdisk
  94.  *
  95.  * Returns: -1 if error, otherwise: 0=drive A, 1=drive B, and so on.
  96.  */
  97. int getdisk()
  98. {
  99.    unsigned d;
  100.    _dos_getdrive(&d);
  101.   return ((int)d - 1);
  102. }
  103.  
  104. /*
  105.  * setdisk: 0=drive A, 1=drive B, and so on.
  106.  *
  107.  * Returns: total number of drive available
  108.  *
  109.  */
  110. int setdisk( int drive )
  111. {
  112.   unsigned numdrives;
  113.   _dos_setdrive((unsigned) (drive + 1), &numdrives);
  114.    return numdrives;
  115. }
  116.  
  117. #  endif /* ?!__TURBOC__ */
  118.  
  119. #  if 0
  120. /* function used if we want to fake stat info instead of failing the file,
  121.  * but I cannot find a case where stat fails after findfirst/findnext succeeds.
  122.  */
  123.  
  124. /* fill stat structure given the DOS findfirst structure */
  125. static void dd_fillstatbuf( FSTRUCT* fb )
  126. {
  127.   struct date fdate;
  128.   struct time ftime;
  129.   /*
  130.    *  convert struct ffblk date/time format -> dos format
  131.    */
  132.   fdate.da_year = (fb->FDATE>>9) + 1980;
  133.   fdate.da_day  = fb->FDATE & 0x1f;
  134.   fdate.da_mon  = fb->FDATE>>5 & 0xf;
  135.   ftime.ti_hour = fb->FTIME>>11;
  136.   ftime.ti_min  = fb->FTIME>>5 & 0x3f;
  137.   ftime.ti_sec  = 2*(fb->FTIME & 0x1f);
  138.   ftime.ti_hund = 0;
  139.  
  140.   /* convert dos time to t_time format */
  141.   dd_sstat->st_atime =
  142.   dd_sstat->st_mtime =
  143.   dd_sstat->st_ctime = dostounix (&fdate, &ftime);
  144.  
  145.   /*
  146.    * set file mode flags
  147.    */
  148.  
  149.   dd_sstat->st_mode = S_IREAD;
  150.  
  151.   if (fb->ff_attrib & DD_DIREC) dd_sstat->st_mode |= (S_IFDIR | S_IEXEC);
  152.   else if (fb->ff_attrib & DD_DEVICE) /* non-documented findfirst attribute */
  153.     dd_sstat->st_mode |= S_IFCHR;
  154.   else dd_sstat->st_mode |= S_IFREG;
  155.   if (!(fb->ff_attrib & DD_RDONLY)) dd_sstat->st_mode |= S_IWRITE;
  156.  
  157.   /* other msdos stat fields not used by dosdir */
  158.   dd_sstat->st_uid   = dd_sstat->st_gid = 0;
  159.   dd_sstat->st_size  = fb->FSIZE;
  160.   dd_sstat->st_nlink = 1;
  161.   dd_sstat->st_ino   = 0;
  162.   dd_sstat->st_rdev  = dd_sstat->st_dev = fb->ff_attrib & DD_DEVICE ? -1 : 3;
  163. }
  164. #  endif
  165.  
  166. static int dd_initstruct( dd_ffblk* fb )
  167. {
  168.   fb->dd_name = fb->dos_fb.FNAME;
  169.  
  170.   /*  ".." entry refers to the directory entry of the cwd and *NOT* the
  171.    *   parent directory, so we use "." instead.
  172.    */
  173.   if (stat(!strcmp(fb->dd_name, "..") ? "." : fb->dd_name, &dd_sstat))
  174.     return -1; /* stat failed! */
  175.  
  176.   fb->dd_time = dd_sstat.st_mtime;
  177.   fb->dd_size = fb->dos_fb.FSIZE;
  178.   fb->dd_mode = fb->dos_fb.FATTRIB & DD_DOSATTRIBS |
  179.                   dd_sstat.st_mode & ~DD_DOSATTRIBS;
  180.   return 0;
  181. }
  182.  
  183. /*
  184.  * Function:    dd_findnext
  185.  *
  186.  * Purpose:    Use dd_findnext after dd_findfirst to find the remaining files
  187.  *
  188.  * Returns:    zero if successful, otherwise, it returns a -1
  189.  *         and sets errno either to the constant ENOENT indicating
  190.  *              that the file could not be found, or to ENMFILE
  191.  *        signifying that there are no more files.
  192.  *
  193.  *  Parms:
  194.  *      dd_ffblk* fb  = structure to hold results of search
  195.  */
  196. int dd_findnext( dd_ffblk* fb )
  197. {
  198.     int rc;
  199.     /* repeat until file info is initialized or no more files are left */
  200.     while ((rc=FNEXT(&fb->dos_fb)) == 0 && (rc=dd_initstruct(fb)) != 0);
  201.     return rc;
  202. }
  203.  
  204. /*
  205.  * Function:    dd_findfirst
  206.  *
  207.  * Purpose:    Find file matching specification in specified directory
  208.  *        given directory information
  209.  *
  210.  * Returns:    zero if successful, otherwise, it returns a -1
  211.  *        and sets errno either to the constant ENOENT indicating
  212.  *        that the file could not be found, or to ENMFILE
  213.  *        signifying that there are no more files.
  214.  *
  215.  *  Parms:
  216.  *      char *filespec    = filename to search for including path
  217.  *      dd_ ffblk* fb     = structure to hold results of search
  218.  *      int attrib        = file attributes to match
  219.  */
  220. int dd_findfirst( const char *path, dd_ffblk *fb, int attrib )
  221. {
  222.     int rc;
  223.     if ((rc = FFIRST( path, &fb->dos_fb, attrib & DD_DOSATTRIBS)) == 0)
  224.     {
  225.     if ((rc = dd_initstruct(fb)) != 0) /* initialization failed? */
  226.             rc = dd_findnext( fb );
  227.     }
  228.     return rc;
  229. }
  230.  
  231. #elif defined (VMS)
  232.  
  233. int dd_findnext( dd_ffblk* fb )
  234. {
  235.   int rc;
  236.   while ((rc = SYS$SEARCH(&fb->fab, 0, 0)) == RMS$_NORMAL)
  237.   {
  238.     char *s;
  239.     fb->rsa[fb->nam.nam$b_rsl] = '\0'; /* terminate filename */
  240.     if (stat(fb->rsa, &dd_sstat)) /* if stat fails then we have no */
  241.     continue;          /* priviledge to read file, so skip it */
  242.     if (dd_sstat.st_mode & S_IFDIR && !(fb->dd_attribs & DD_DIREC))
  243.     continue;
  244.     s = strchr(fb->rsa, DIR_END);
  245.     fb->dd_name = s ? s + 1 : fb->rsa;
  246.     if (dd_match(fb->dd_name, fb->filespec, 1))
  247.       {
  248.     fb->dd_size  = dd_sstat.st_size;
  249.     fb->dd_time  = dd_sstat.st_mtime;
  250.     fb->dd_mode  = dd_sstat.st_mode;
  251.     return 0;    /* OK: match found */
  252.       }
  253.     } /* while */
  254.  
  255.   memset(fb, 0x0, sizeof(dd_ffblk));    /* Invalidate structure */
  256.   errno = ENOENT;            /* No file found */
  257.   return -1;                /* Search failed */
  258. }
  259.  
  260. int dd_findfirst( const char *path, dd_ffblk *fb, int attrib )
  261. {
  262.   char *s;
  263.   strcpy(fb->path, path);
  264.   s = strchr(fb->path, DIR_END);
  265.   if (!s)
  266.     s = strrchr(fb->path, ':'); /* check device/node */
  267.   if (s)
  268.     {
  269.     strncpy(fb->rms_filespec, fb->path, s - fb->path + 1);
  270.     strcat(fb->rms_filespec, "*.*");
  271.     fb->filespec = s + 1;
  272.     printf("filespec = %s\n", fb->rms_filespec);
  273.     }
  274.   else
  275.     {
  276.     strcpy(fb->rms_filespec, "*.*");
  277.     fb->filespec = fb->path;
  278.     }
  279.  
  280.   /* if no version number specified then add one */
  281.   s = strchr(fb->path, ';');
  282.   if (!s) strcat(fb->path, ";*");
  283.  
  284.   fb->fab = cc$rms_fab;
  285.   fb->nam = cc$rms_nam;
  286.   fb->fab.fab$l_dna = &fb->rms_filespec;
  287.   fb->fab.fab$b_dns = strlen(fb->rms_filespec);
  288.   fb->fab.fab$l_nam = &fb->nam;
  289.   fb->nam.